package org.unit.testmgmt.ui.table;

import java.util.Iterator;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ComboBoxViewerCellEditor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.unit.testmgmt.messages.Messages;

/**
 * The table viewer base class.
 * 
 * @author Robert Streng
 * 
 */
public class TableViewerBase {

	/**
	 * Content provider
	 * 
	 * @author Robert Streng
	 * 
	 */
	class ContentProvider implements IStructuredContentProvider, ITableEntryListListener {
		@Override
		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
			if (newInput != null)
				((TableEntryList<?>) newInput).addChangeListener(this);
			if (oldInput != null)
				((TableEntryList<?>) oldInput).removeChangeListener(this);
		}

		@Override
		public void dispose() {
			tblEntryList.removeChangeListener(this);
		}

		@Override
		public Object[] getElements(Object parent) {
			return tblEntryList.getTableEntries().toArray();
		}

		@Override
		public void addTableEntry(ITableEntry tblEntry) {
			for (TableViewerColumn column : tblEntry.getTableViewerColumns()) {
				Iterator<ITableViewerColumnListener> listener = column.getChangeListener()
						.iterator();
				while (listener.hasNext()) {
					listener.next().tblEntryAdded(column, tblEntry.getValue(column));
				}
			}

			tableViewer.add(tblEntry);
		}

		@Override
		public void removeTableEntry(ITableEntry tblEntry) {
			for (TableViewerColumn column : tblEntry.getTableViewerColumns()) {
				Iterator<ITableViewerColumnListener> listener = column.getChangeListener()
						.iterator();
				while (listener.hasNext()) {
					listener.next().tblEntryRemoved(column, tblEntry.getValue(column));
				}
			}

			tableViewer.remove(tblEntry);
		}

		@Override
		public void updateTableEntry(ITableEntry tblEntry, TableViewerColumn column,
				Object value, Object oldValue) {

			Iterator<ITableViewerColumnListener> listener = column.getChangeListener().iterator();
			while (listener.hasNext()) {
				listener.next().tblEntryChanged(column, value, oldValue);
			}

			tableViewer.update(tblEntry, null);
		}
	}

	private TableViewerColumns columns;

	public TableViewerColumns getTableViewerColumns() {
		return columns;
	}

	/**
	 * @param parent
	 */
	public TableViewerBase(Composite parent, TableViewerColumns columns,
			TableEntryList<? extends ITableEntry> tblEntryList) {
		this.columns = columns;
		this.tblEntryList = tblEntryList;
		this.addChildControls(parent);
	}

	private Table table;
	private TableViewer tableViewer;
	private TableEntryList<? extends ITableEntry> tblEntryList;

	/**
	 * Creates the table.
	 * 
	 * @param parent
	 */
	private void createTable(Composite parent) {
		int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION
				| SWT.HIDE_SELECTION;

		table = new Table(parent, style);

		table.setLayout(new GridLayout());
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalSpan = 3;
		table.setLayoutData(gridData);

		table.setLinesVisible(true);
		table.setHeaderVisible(true);

		createTableColumns(table);
	}

	/**
	 * Creates the table columns.
	 * 
	 * @param table
	 */
	private void createTableColumns(Table table) {

		TableColumn newColumn;
		int style;

		for (TableViewerColumn column : getTableViewerColumns().getColumns()) {
			style = column.getStyle();

			newColumn = new TableColumn(table, style);
			newColumn.setText(column.getName());

			if (column.getWidth() == -1) {
				newColumn.pack();
			}
			else {
				newColumn.setWidth(column.getWidth());
			}
		}
	}

	/**
	 * Adds the child controls.
	 * 
	 * @param parent
	 */
	private void addChildControls(Composite parent) {
		Composite composite = new Composite(parent, SWT.SCROLLBAR_OVERLAY);

		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.FILL_BOTH);
		composite.setLayoutData(gridData);

		// table and buttons
		GridLayout layout = new GridLayout(3, false);
		layout.marginWidth = 5;
		composite.setLayout(layout);

		// table
		createTable(composite);

		// tableViewer
		createTableViewer();
		tableViewer.setContentProvider(new ContentProvider());
		tableViewer.setLabelProvider(new LabelProviderBase());
		tableViewer.setInput(tblEntryList);

		// buttons
		createButtons(composite);
	}

	/**
	 * Creates the TableViewer
	 */
	private void createTableViewer() {

		tableViewer = new TableViewer(table);
		tableViewer.setUseHashlookup(true);
		tableViewer.setColumnProperties(getTableViewerColumns().getColumnsStringArray());

		CellEditor[] editors = new CellEditor[getTableViewerColumns().getColumns().size()];
		TableViewerColumn column;
		TextCellEditor textEditor;

		for (int i = 0; i < getTableViewerColumns().getColumns().size(); i++) {
			column = getTableViewerColumns().getColumn(i);

			if (column.isCombobox()) {
				editors[i] = new ComboBoxViewerCellEditor(table, SWT.READ_ONLY);
				column.setEditor(editors[i]);
			}
			else {
				switch (column.getType()) {
				case STRING:
					textEditor = new TextCellEditor(table);
					((Text) textEditor.getControl()).setTextLimit(60);
					editors[i] = textEditor;
					break;

				case BOOLEAN:
					editors[i] = new ComboBoxViewerCellEditor(table, SWT.READ_ONLY);
					break;

				case INTEGER:
					textEditor = new TextCellEditor(table);
					((Text) textEditor.getControl()).addVerifyListener(new VerifyListener() {
						public void verifyText(VerifyEvent e) {
							e.doit = e.text.matches("-?[0-9]*"); //$NON-NLS-1$
						}
					});
					editors[i] = textEditor;
					break;
				default:
					textEditor = new TextCellEditor(table);
					((Text) textEditor.getControl()).setTextLimit(60);
					editors[i] = textEditor;
					break;
				}

				column.setEditor(editors[i]);
			}
		}

		tableViewer.setCellEditors(editors);
		tableViewer.setCellModifier(new CellModifier(this));
	}

	/**
	 * Creates the buttons.
	 * 
	 * @param parent
	 */
	private void createButtons(Composite parent) {
		// add
		Button btnAdd = new Button(parent, SWT.PUSH | SWT.CENTER);
		btnAdd.setText(Messages.TableViewerBase_Add);

		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
		gridData.widthHint = 80;
		btnAdd.setLayoutData(gridData);
		btnAdd.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				tblEntryList.createTableEntry(true);
			}
		});

		// copy
		Button btnCopy = new Button(parent, SWT.PUSH | SWT.CENTER);
		btnCopy.setText(Messages.TableViewerBase_Copy);
		gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
		gridData.widthHint = 80;
		btnCopy.setLayoutData(gridData);

		btnCopy.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
				if (!selection.isEmpty()) {
					ITableEntry tblEntry = (ITableEntry) selection.getFirstElement();
					if (tblEntry != null) {
						ITableEntry newTblEntry = tblEntry.clone();
						if (newTblEntry != null)
							tblEntryList.addUncheckedTableEntry(newTblEntry);
					}
				}
			}
		});

		// delete
		Button btnDelete = new Button(parent, SWT.PUSH | SWT.CENTER);
		btnDelete.setText(Messages.TableViewerBase_Delete);
		gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
		gridData.widthHint = 80;
		btnDelete.setLayoutData(gridData);

		btnDelete.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				ITableEntry tblEntry = (ITableEntry) ((IStructuredSelection) tableViewer
						.getSelection()).getFirstElement();
				if (tblEntry != null) {
					tblEntryList.removeTableEntry(tblEntry);
				}
			}
		});
	}

	/**
	 * @return selected item
	 */
	public ISelection getSelection() {
		return tableViewer.getSelection();
	}

	/**
	 * @param selection
	 */
	public void setSelection(ISelection selection) {
		tableViewer.setSelection(selection);
	}

	/**
	 * @return table entry list
	 */
	public TableEntryList<? extends ITableEntry> getTableEntryList() {
		return tblEntryList;
	}

	/**
	 * @return wizard.controller
	 */
	public Control getControl() {
		return table.getParent();
	}

	/**
	 * @return table
	 */
	public Table getTable() {
		return table;
	}

	/**
	 * @return table viewer
	 */
	public TableViewer getTableViewer() {
		return tableViewer;
	}
}